package org.sqlproc.engine.impl.type;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

import org.hibernate.Query;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sqlproc.engine.SqlRuntimeException;

/**
 * The common ancestor of all SQL META Types. These internal types are devoted for the special processing of the
 * input/output values.
 * 
 * @author <a href="mailto:Vladimir.Hudec@gmail.com">Vladimir Hudec</a>
 */
public abstract class SqlMetaType {

    /**
     * The internal type, which means special processing of the input/output value.
     */
    protected final Logger logger = LoggerFactory.getLogger(getClass());

    /**
     * Initializes the attribute of the result class with output values from SQL query execution.
     * 
     * @param resultInstance
     *            the instance of the result class
     * @param attributeName
     *            the name of the attribute in the result class
     * @param resultValue
     *            Query execution output value
     * @param ingoreError
     *            ignore inproper output value handling
     * @throws org.sqlproc.engine.SqlRuntimeException
     *             in the case of any problem with output values handling
     */
    public abstract void setResult(Object resultInstance, String attributeName, Object resultValue, boolean ingoreError)
            throws SqlRuntimeException;

    /**
     * Bind an input value to a named query parameter.
     * 
     * @param query
     *            the object-oriented representation of a Hibernate query
     * @param paramName
     *            the name of the parameter
     * @param inputValue
     *            the possibly-null parameter value, a dynamic input value
     * @param ingoreError
     *            ignore inproper input value handling
     * @throws org.sqlproc.engine.SqlRuntimeException
     *             in the case of any problem with input values handling
     */
    public abstract void setParameter(Query query, String paramName, Object inputValue, Class<?> inputType,
            boolean ingoreError) throws SqlRuntimeException;

    /**
     * Singleton instance of default type.
     */
    public static final SqlMetaType DEFAULT = new SqlDefaultType();
    /**
     * Singleton instance of Integer based enumeration type.
     */
    public static final SqlMetaType ENUM_INT = new SqlEnumIntegerType();
    /**
     * Singleton instance of String based enumeration type.
     */
    public static final SqlMetaType ENUM_STRING = new SqlEnumStringType();
    /**
     * Singleton instances of generic types.
     */
    public static final SqlMetaType[] TYPES = { new SqlBigDecimalType(), new SqlBigIntegerType(), new SqlBooleanType(),
            new SqlByteArrayType(), new SqlByteType(), new SqlCharType(), new SqlDateTimeType(), new SqlDateType(),
            new SqlDoubleType(), ENUM_INT, ENUM_STRING, new SqlFloatType(), new SqlFromDateType(),
            new SqlIntegerType(), new SqlLongType(), new SqlShortType(), new SqlStringType(), new SqlTimestampType(),
            new SqlTimeType(), new SqlToDateType() };

    /**
     * The immutable map between a Java class type and an internal type.
     */
    public static Map<Class<?>, SqlMetaType> CLASS_TO_TYPE_MAP = new HashMap<Class<?>, SqlMetaType>();
    /**
     * The immutable map between a String representation of an internal types and an internal types.
     */
    public static Map<String, SqlMetaType> META_TO_TYPE_MAP = new HashMap<String, SqlMetaType>();

    /**
     * Static init.
     */
    static {
        for (SqlMetaType type : TYPES) {
            if (type instanceof SqlGenericType) {
                for (Class<?> classType : ((SqlGenericType) type).getClassTypes())
                    CLASS_TO_TYPE_MAP.put(classType, type);
                for (String metaType : ((SqlGenericType) type).getMetaTypes())
                    META_TO_TYPE_MAP.put(metaType.toUpperCase(), type);
            }
        }
        CLASS_TO_TYPE_MAP = Collections.unmodifiableMap(CLASS_TO_TYPE_MAP);
        META_TO_TYPE_MAP = Collections.unmodifiableMap(META_TO_TYPE_MAP);
    }
}
